package com.wang.socket;

import com.wang.packpojo.ConMsg;
import com.wang.util.GetByteEncodeUtil;
import com.wang.util.ModBusUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;

/**
 * 自定义解码器
 *
 * @author wcy
 */
public class CustomDecoder2 extends ByteToMessageDecoder {

    private final int BASE_LENGTH = 1;

    //private String heart = "METER";
    private String reg = "DSDEVREG";
    int num = 0;

    /**
     * 十六进制字符串数组解析
     *
     * @param ctx
     * @param in   传入数据
     * @param list 添加解码消息
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list) throws Exception {


        int beginIndex;//记录包开始位置


        while (true) {

            //获取包头开始的index
            beginIndex = in.readerIndex();
            // 将当前的readerIndex备份到markedReaderIndex中
            in.markReaderIndex();


            //获取字节可读取长度
            int reablesLength = in.readableBytes();


            //1、判断是不是注册包
            //--------------------------------------------

            //若数据包小于注册包数量  直接退出
            if (reablesLength < reg.getBytes().length) {
                return;
            }
            //读取前8位字节 判断是不是注册包数据
            byte[] bytes2 = new byte[reg.getBytes().length];
            in.readBytes(bytes2);

            String encoding1 = GetByteEncodeUtil.getEncoding(bytes2);
            String data2 = new String(bytes2, encoding1);
            if (data2.equals(reg)) {
                //继续往下读  读到；结束
                //定义下标
                int index = 0;
                //定义包含;的标志
                boolean containFlag = false;

                for (int i = 0; i < reablesLength - reg.getBytes().length; i++) {

                    //读取一个字节
                    byte[] bytesFlag = new byte[1];
                    in.readBytes(bytesFlag);

                    String encoding2 = GetByteEncodeUtil.getEncoding(bytesFlag);
                    String flag = new String(bytesFlag, encoding2);

                    if (flag.equals(";")) {
                        index = i;
                        containFlag = true;
                        break;
                    }
                }
                if (containFlag) {
                    //重置读取字节位置
                    in.resetReaderIndex();
                    //读取完整的注册包数据
                    byte[] regDatas = new byte[reg.getBytes().length + index + 1];
                    in.readBytes(regDatas);

                    String encoding3 = GetByteEncodeUtil.getEncoding(regDatas);
                    String ctxData = new String(regDatas, encoding3);
                    //System.out.println(ctxData);

                    //添加数据
                    list.add(ctxData.replace(";", ""));
                    //回收已读字节
                    in.discardReadBytes();
                    return;
                } else {
                    //如果不包含 代表数据不全，返回读的指针 等待下一次的数据到期在读
                    in.readerIndex(beginIndex);
                    return;
                }


            }


            //一、 先判断全局变量已注册的是否包含此设备
            String address = getRemoteAddress(ctx);

            String isContain = "false";
            ConMsg conMsg = null;
            if (SocketMap.mRegPassDeviceMap.containsKey(address)) {
                isContain = "mContain";
                conMsg = SocketMap.mRegPassDeviceMap.get(address);


            }
            if (SocketMap.jRegPassDeviceMap.containsKey(address)) {
                isContain = "jContain";
                conMsg = SocketMap.jRegPassDeviceMap.get(address);

            }
            if (isContain.equals("false")) {
                return;
            }


            //判断是不是心跳包  json modbus 通用
            //重置字节读取下标
            in.resetReaderIndex();
            //---------------------------------
            //2、判断是不是心跳包
            //若数据包小于心跳包数量  直接退出
            //判断注册包 先判断设备是不是已经注册
            if (!isContain.equals("false")) {


                String heartBeat = conMsg.getConHeart().getHeartBeat();
                if (reablesLength < heartBeat.getBytes().length) {
                    return;
                }
                //先读前心跳包长度 判断是是不是心跳包数据
                byte[] bytes = new byte[heartBeat.getBytes().length];
                in.readBytes(bytes);

                String encoding4 = GetByteEncodeUtil.getEncoding(bytes);
                String data = new String(bytes, encoding4);
                if (data.equals(heartBeat)) {

                    String encoding5 = GetByteEncodeUtil.getEncoding(bytes);
                    String ctxData = new String(bytes, encoding5);
                    // System.out.println("心跳包:"+new String(ctxData +":"+(num++));
                    //添加数据

                    list.add(ctxData);
                    //回收已读字节
                    in.discardReadBytes();
                    return;
                }

            }


            //3、判断是不是json数据
            //--------------------------------
            //重置字节读取下标
            //重置字节读取下标
            in.resetReaderIndex();
            if (isContain.equals("jContain")) {


                //方式  读取左大括号 +1   读取到右括号-1
                //先读取第一个字节 是否是 { 如果是依次读字节
                byte[] byteleft = new byte[1];
                in.readBytes(byteleft);

                String encoding6 = GetByteEncodeUtil.getEncoding(byteleft);
                String firstData = new String(byteleft, encoding6);
                if (firstData.equals("{")) {
                    //下标
                    int indexFlag = 0;
                    int intFlag = 0;


                    indexFlag++;
                    intFlag++;
                    //依次往下读
                    //读取一个字节 -1 代表已经读过一个字节
                    for (int i = 0; i < reablesLength - 1; i++) {

                        byte[] bytesFlag = new byte[1];
                        in.readBytes(bytesFlag);
                        indexFlag++;
                        String encoding7 = GetByteEncodeUtil.getEncoding(bytesFlag);
                        String flag = new String(bytesFlag, encoding7);
                        if (flag.equals("{")) {
                            //标识+1
                            intFlag++;
                        }
                        if (flag.equals("}")) {
                            //标识-1
                            intFlag--;
                        }
                        if (intFlag == 0) {
                            //如果标识为0 查询到所有json数据
                            break;
                        }
                    }

                    if (intFlag == 0) {


                        //截取数据
                        //重置字节读取下标
                        in.resetReaderIndex();
                        byte[] jsonBytes = new byte[indexFlag];
                        in.readBytes(jsonBytes);
                        String encoding8 = GetByteEncodeUtil.getEncoding(jsonBytes);
                        System.out.println("编码格式:" + encoding8);
                        String jsonData = new String(jsonBytes, encoding8);

                        System.out.println(jsonData);
                        //添加数据
                        list.add(jsonData);
                        //回收已读字节
                        in.discardReadBytes();
                        //System.out.println("json数据:"+jsonData);
                        return;

                    } else {

                        //如果不包含 代表数据不全，返回读的指针 等待下一次的数据到期在读
                        in.readerIndex(beginIndex);
                        return;
                    }


                }
            }

            //重置读取位
            in.resetReaderIndex();
            if (isContain.equals("mContain")) {
                //最后一步 modbus数据读取

                //modbus数据读取前3个字节 获取数据长度
                byte[] mdatas = new byte[3];
                in.readBytes(mdatas);
                //截取数据位长度
                String mlength = bytes2HexString(mdatas).split(" ")[2];

                //重置读取位
                in.resetReaderIndex();

                Integer length = hex2decimal(mlength);
                System.out.println("长度："+length);

                int totalDataLength = 3 + length + 2;  //地址 +功能 +数据长度  3   加上数据长度 +  校验位长度2
                //如果可读数据位长度小于  数据位长度  返回 等待下一次数据到期在读
                if (reablesLength < totalDataLength) {
                    in.readerIndex(beginIndex);
                    return;
                }
                byte[] mdatas2 = new byte[totalDataLength];

                in.readBytes(mdatas2);


                //计算modbus数据合法性
                //先将bytes 转换成16进制字符串
                String baseData = ModBusUtil.bytes2HexString(mdatas2);


                String baseDataStr = baseData.replaceAll(" ", "");
                String[] baseDatas = baseData.split(" ");

                //要校验的数据
                String[] checkDatas = Arrays.copyOfRange(baseDatas, 0, baseDatas.length - 2);
                StringBuffer sb1 = new StringBuffer();
                for (String s : checkDatas) {
                    sb1.append(s);
                }

                byte[] checkBytes = ModBusUtil.HexString2Bytes(sb1.toString());


                //计算crc值
                String checkCrc2 = ModBusUtil.getCRC3(checkBytes);
                //截取原有crc值
                String checkCrc1 = baseDataStr.substring(baseDataStr.length() - 4);

                if (checkCrc1.equals(checkCrc2)) {
                    //添加数据
                    list.add(baseData);
                    //System.out.println("数据:"+bytes2HexString(mdatas2));
                    //回收已读字节
                    in.discardReadBytes();
                    break;
                    //System.out.println("数据:" + new String(finData, "GBK"));
                } else {
                    break;

                }

            }
        }


    }


    /*
     * 字节数组转16进制字符串
     */
    public static String bytes2HexString(byte[] b) {
        String r = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            r += hex.toUpperCase() + " ";
        }
        return r;
    }

    // 16进制字符串转换10进制
    public static int hex2decimal(String hex) {
        return Integer.parseInt(hex, 16);
    }

    //获取连接ctx的地址
    public String getRemoteAddress(ChannelHandlerContext ctx) {
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = ipSocket.getAddress().getHostAddress();
        Integer port = ipSocket.getPort();
        String ip = clientIp + ":" + port;
        return ip;
    }

}


